package com.warmheart.base.filter;

import java.io.IOException;
import java.util.Date;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;

import com.warmheart.base.config.SysConfig.Encrypt;
import com.warmheart.base.executor.TraceContext;
import com.warmheart.core.util.JsonResponseUtil;
import com.warmheart.core.util.UUIDGenerator;
import com.warmheart.core.util.aes.AESUtil;
import com.warmheart.core.util.rsa.RSAUtil;

/**
 * 
 * @ClassName: EncryptFilter
 * @Description: 加密过滤器(请求和响应使用同一个加密KEY，所以响应的加密的前提是请求加密)
 * @author ZhangJianyang
 * @date 2025-06-16 09:37:02
 *
 */
public abstract class EncryptFilter implements Filter {

    private static Logger logger = LoggerFactory.getLogger(EncryptFilter.class);

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        if (!encrypt().getParam().getStatus() && !encrypt().getResult().getStatus()) {
            chain.doFilter(request, response);
            return;
        }
        Date startTime = new Date();
        String preSpanId = TraceContext.getSpan();
        TraceContext.setSpan();
        logger.info("----------------------------加密处理开始----------------------------");
        try {
            if (request instanceof HttpServletRequest) {
                HttpServletRequest hRequest = (HttpServletRequest) request;
                HttpServletResponse hResponse = (HttpServletResponse) response;
                // 这里只处理POST请求
                if (hRequest.getMethod().equalsIgnoreCase("post")) {
                    if (encrypt().getParam().getStatus()) {
                        String rsaSecKey = hRequest.getHeader("SEC-KEY");
                        if (StringUtils.isBlank(rsaSecKey)) {
                            rsaSecKey = UUIDGenerator.getUUID();
                        }
                        logger.info("原始加密KEY：" + rsaSecKey);
                        // 模拟前端公钥加密
                        String realRsaSecKey = RSAUtil.encryptByPublic(rsaSecKey, null);
                        logger.info("解密前加密KEY：" + realRsaSecKey);
                        // 服务端私钥解密
                        String secKey = RSAUtil.decryptByPrivate(realRsaSecKey, null);
                        logger.info("解密后加密KEY：" + secKey);
                        String contentType = hRequest.getContentType();
                        if (StringUtils.isNotBlank(contentType) && contentType.contains("multipart/form-data")) {
                            // 将转化后的 request 放入过滤链中
                            hRequest = new StandardServletMultipartResolver().resolveMultipart(hRequest);
                        }
                        EncryptRequestWrapper requestWrapper = new EncryptRequestWrapper(hRequest, secKey);
                        logger.info("解密前参数数据：" + requestWrapper.getSrcBody());
                        logger.info("解密后参数数据：" + requestWrapper.getRequestBody());
                        if (encrypt().getResult().getStatus()) {
                            EncryptResponseWrapper responseWrapper = new EncryptResponseWrapper(hResponse);
                            chain.doFilter(requestWrapper, responseWrapper);
                            if (responseWrapper.getStatus() == 200) {
                                String resp = responseWrapper.getTextContent();
                                logger.info("加密前返回数据：" + resp);
                                // 加密处理返回
                                String srcStr = AESUtil.toEncryptParam(resp, secKey);
                                logger.info("返回数据加密完成");
                                logger.info("加密后返回数据：" + srcStr);
                                // 重新解密(保持调试数据正常)
                                String resourceStr = AESUtil.toDecryptParam(srcStr, secKey);
                                JsonResponseUtil.writerJsonStr(hResponse, resourceStr);
                            }
                        } else {
                            chain.doFilter(requestWrapper, hResponse);
                        }
                    } else {
                        chain.doFilter(hRequest, hResponse);
                    }
                } else {
                    chain.doFilter(hRequest, hResponse);
                }
            } else {
                chain.doFilter(request, response);
            }
        } catch (Exception e) {
            logger.error("加密过滤器异常：" + e.getMessage(), e);
        } finally {
            Long nextSpanCost = TraceContext.getSpanCost();
            Date endTime = new Date();
            Long currSpanCost = endTime.getTime() - startTime.getTime() - nextSpanCost;
            logger.info("加密处理耗时{}ms", currSpanCost);
            logger.info("----------------------------加密处理结束----------------------------");
            TraceContext.resetSpanCost(endTime.getTime() - startTime.getTime());
            TraceContext.resetSpan(preSpanId);
        }
    }

    /**
     * 
     * @Title: encrypt
     * @Description: 加密解密配置
     * @author ZhangJianyang
     * @return
     */
    protected abstract Encrypt encrypt();
}
